<template>

  <div class="flex flex-row gap-5 my-2">
    <div class="form-control">
      <label class="label"></label>
      <input type="text" placeholder="your username" class="input input-bordered" v-model="userId"
             disabled/>
    </div>
    <div class="form-control">
      <label class="label"></label>
      <input type="text" placeholder="call contact" class="input input-bordered" v-model="calleeId"
             required/>
    </div>

    <div>
      <button v-if="isCommunicating" class="btn" @click="clickHangup">挂断</button>
      <button v-else class="btn" @click="clickCall">Call视频</button>

      <button v-if="isCalling" class="btn" @click="clickCancel">Cancel</button>
    </div>

    <div v-if="isRing">
      <button class="btn" @click="clickAccept">接通</button>
      <button class="btn" @click="clickReject">拒接</button>
    </div>
  </div>

  <!--状态栏-->
  <div class="flex">
    <div class="flex-initial w-64 ">
      <label v-if="isMicrophone" class="swap">
        <input type="checkbox" v-model="isAudioFlag" @change="toggleAudio"/>
        <IconVolumeOff class="swap-off fill-current"/>
        <IconVolumeOn class="swap-on fill-current"/>
      </label>
      <IconVolumeLost v-else/>
    </div>
    <div class="flex-initial ">
      <div v-if="isCalling" role="alert" class="alert alert-info alert-soft">
        <span>呼叫对方中...</span>
      </div>
      <div v-if="isRing" role="alert" class="alert alert-info alert-soft">
        <span>您有新电话...</span>
      </div>
      <div v-if="isCommunicating" role="alert" class="alert alert-info alert-soft">
        <span>正在通话中...</span>
      </div>
    </div>
  </div>

  <div>

    <div class="relative bg-orange-200 rounded-lg max-w-3xl h-96">
      <!--
        width="240" height="320"
        width="960" height="1280"
      -->
      <video ref="localVideoRef" class="max-h-32 absolute bottom-0 left-0"></video>
      <video ref="remoteVideoRef" class="max-h-96 "></video>
    </div>
  </div>

</template>


<script setup>
import {ref} from "vue";
import 'element-plus/es/components/message/style/css';
import {ElMessage} from 'element-plus'
import {Callee, Caller, CallStatus, Signal} from "@/models/call.ts";
import {getLocalStream, hasAudioTrack, hasMicrophone} from "@/utils/my_media_device.js"
import Peer, {PeerErrorType} from "peerjs";
import IconVolumeOn from "@/components/icons/IconVolumeOn.vue";
import IconVolumeOff from "@/components/icons/IconVolumeOff.vue";
import IconVolumeLost from "@/components/icons/IconVolumeLost.vue";
import {randomName} from "@/api/data_mock.js";

const localUserId = randomName()
const userId = ref(localUserId)
const calleeId = ref('')

let local_stream = ref(null); // local video stream

// 本地视频
const localVideoRef = ref();
// 远程视频
const remoteVideoRef = ref();

//是否正在呼叫
const isCalling = ref(false);
//是否来电了
const isRing = ref(false);
//是否正在通话
const isCommunicating = ref(false);

const isAudioFlag = ref(true);

const isMicrophone = ref(true);

let caller = null; //主动方
let callee = null; //接收方

const videoSize = {
  width: 960,
  height: 1280,
}

/**
 iceTransportPolicy：默认all，可选值：all、relay
 */
const pcConfig = {
  'iceServers': [
    {
      'urls': [
        'stun:101.43.102.215:3478'
      ],
      'username': "goddess",
      'credential': "goddess00"
    }, {
      'urls': [
        'turn:101.43.102.215:3478'
      ],
      'username': "admin",
      'credential': "123456"
    }
  ]
};

// 192.168.3.106:9000
const signalHost = import.meta.env.VITE_SIGNAL_HOST;
const [ip, port] = signalHost.split(':');
console.log('peer服务 signalHost : ', signalHost);
const peer = new Peer(localUserId, {
  config: pcConfig,
  host: ip,
  port: Number(port),
  secure: false
});

//打开事件回调
peer.on('open', (id) => {
  console.log("[peer] open ... ", id)
});
//关闭事件回调
peer.on('close', (e) => {
  console.log("[peer] close ... e = ", e)
})
//发送错误时回调
peer.on('error', (err) => {
  if (err.type=== PeerErrorType.PeerUnavailable){
    console.log(`[peer] err.type=${err.type} err.message =${err.message}`);

    ElMessage.warning("对方不在线");

    isCalling.value = false;

    caller.close();
    closeCamera(localVideoRef.value);
    closeCamera(remoteVideoRef.value);
    return;
  }
  console.error(`[peer] err ... err.type=${err.type} err =`, err);
  ElMessage.error("出现错误 cause:"+err.message);
});
//断开连接事件回调：与 Peer服务器的 WebSocket 连接断开
peer.on('disconnected', (e) => {
  console.log("[peer] websocket 已断开 ... e = ", e)
  console.log("尝试重连 peer ...")
  peer.reconnect();
})

//连接事件回调
peer.on('connection', (dataConn) => {
  console.log("[peer] connection ... ")

  if (isCommunicating.value) {
    console.warn("正在占线中.")
  } else {
    isRing.value = true;
    callee = new Callee(localUserId, dataConn);

    dataConn.on('data', (msg) => {
      console.log('Received: ' + JSON.stringify(msg));
      if (!msg) {
        return;
      }
      signalCallback(msg.command);
    })
  }
});

//呼叫事件回调。别人call我时的回调
peer.on('call', async (mediaConn) => {
  console.log("[peer] call ...");
  callee.answerTalk(remoteVideoRef.value, mediaConn); //和对方开始通话
})

const signalCallback = command => {
  if (command === Signal.SetCallType) {
    return;
  }

  isRing.value = false;
  isCommunicating.value = false;

  //如果对方同意，再call对方
  if (command === Signal.ACCEPT) {
    console.log("对方已接听...");
    isCommunicating.value = true;
    caller.value.doTalk(remoteVideoRef.value); //真正调用call接口去通话

    return;
  }
  if (command === Signal.CANCEL) {
    console.log("对方已取消r...")
    ElMessage.info("对方已取消");
    callee.close();
    closeCamera(localVideoRef.value);
    closeCamera(remoteVideoRef.value)
  } else if (command === Signal.HANGUP) {
    console.log("对方已挂断r...")
    ElMessage.info("对方已挂断");
    callee.close();
    closeCamera(localVideoRef.value);
    closeCamera(remoteVideoRef.value)
  }
};

const clickCancel = () => {
  isCalling.value = false;
  if (caller) {
    caller.cancel()
    closeCamera(localVideoRef.value);
    closeCamera(remoteVideoRef.value);
  }
}

/**
 * 开始呼叫
 */
const clickCall = () => {
  if (!calleeId.value) {
    console.warn("缺少calleeId")
    return;
  }

  if (userId.value === calleeId.value) {
    console.warn("calleeId不能是自己")
    return;
  }

  if (isCalling.value) {
    return;
  }

  isCalling.value = true;

  //添加本地媒体流（不能放自己的声音）
  getLocalStream().then(localStream => {
        console.debug(`>>> 本地流 stream.id=${localStream.id}. 是否含有音轨? ${hasAudioTrack(localStream)} `)
        local_stream.value = localStream;

        caller = new Caller(userId.value, calleeId.value, peer);
        caller.localStream = localStream;

        caller.call(1,(command) => {
          isCalling.value = false;

          //如果对方同意，再call对方
          if (command === Signal.ACCEPT) {
            console.log("对方已接听m...")
            isCommunicating.value = true;
            caller.doTalk(remoteVideoRef.value)
          }
          else if (command === Signal.HANGUP) {
            console.log("对方已挂断m...")
            caller.close()
            isCommunicating.value = false;
            ElMessage.info("对方已挂断")
            //关掉摄像头
            closeCamera(localVideoRef.value);
            closeCamera(remoteVideoRef.value);
          }
          else if (command === Signal.REJECT) {
            console.log("对方已拒绝m...")
            caller.close()
            ElMessage.info("对方已拒绝")
            //关掉摄像头
            closeCamera(localVideoRef.value);
            closeCamera(remoteVideoRef.value);
          }
        })

        //添加本地媒体流（不能放自己的声音）
        localVideoRef.value.srcObject = localStream;
        localVideoRef.value.muted = true;
        localVideoRef.value.play(); //播放

      })
}

/**
 * 接听
 */
const clickAccept = async () => {
  isRing.value = false;
  isCommunicating.value = true;


  getLocalStream().then(localStream => {
    console.debug(`>>> 本地流 stream.id=${localStream.id}. 是否含有音轨? ${hasAudioTrack(localStream)} `)

    //添加本地媒体流（不能放自己的声音）
    localVideoRef.value.muted = true;
    localVideoRef.value.srcObject = localStream;
    localVideoRef.value.play(); //播放

    local_stream.value = localStream;
    callee?.accept(localStream);
  });
}

/**
 * 拒接
 */
const clickReject = () => {
  isRing.value = false;
  callee.reject()
}
/**
 * 挂断
 */
const clickHangup = () => {
  console.log("click hangup...")

  if (caller) {
    caller.hangup()
  }
  if (callee) {
    callee.hangup()
  }

  isCommunicating.value = false;

  closeCamera(localVideoRef.value);
  closeCamera(remoteVideoRef.value);
}

const closeCamera = (video) => {
  if (video.srcObject) {
    video.srcObject.getTracks().forEach(
        track => {
          track.stop();
        }
    );
    video.srcObject = null;
  }

}

const toggleAudio = () => {
  console.log("isAudioFlag.value = " + isAudioFlag.value)
  // if (local_stream.value) {
  //    const audioTracks = local_stream.value.getAudioTracks();
  //   audioTracks.forEach(track => {
  //     track.enabled = isAudioEnabled.value;
  //   })
  // }
}

hasMicrophone().then(is => {
  isMicrophone.value = is
})
</script>

<style scoped>

</style>
